//============================================================================
// Name        : application.cpp
// Author      : dfoelber
//============================================================================

// INCLUDES //
#include "application.h"
#include "render_manager.h"
#include "graphics/graphics.h"
#include "draw/SDL_draw.h"
#include <iostream>
//////////////

Application* Application::instance = NULL;

/**
* Private constructor
**/
Application::Application() :
	currentX(-1),
	currentY(-1),
	tooltipCounter(0),
	quit(false),
	paused(false),
	showTop(false),
	ended(false)
{
	globalCounter = 0;
}

/**
* Deconstructor
**/
Application::~Application()
{
	if( screen )
		delete screen;
	
	if( layout )
		delete layout;
	
	if( background )
		delete background;
	
	if( playerRegion )
		delete playerRegion;
	
	if( handRegion )
		delete handRegion;
	
	if( alignmentRegion )
		delete alignmentRegion;
	
	if( puzzleRegion )
		delete puzzleRegion;
	
	if( topRegion )
		delete topRegion;
	
	if( queueRegion )
		delete queueRegion;
	
	if( battleRegion )
		delete battleRegion;
}

/**
* Singleton accessor
* 
* @return Singleton instance
**/
Application* Application::GetManager()
{
	if( instance == NULL )
	{
		instance = new Application();
	}
	
	return instance;
}

/**
* Loads everything.
* 
* @return Success
**/
bool Application::Load()
{
	string file;
	if( LINUX_FILESYSTEM )
		file += "/usr/share/xyne/";
	file += PLAYER_FILENAME;
	
	if( !playerSettings.Load(file.c_str()) )
	{
		cout << "ERROR: cannot open player settings!" << endl;
		return false;
	}
	
	// Create the screen
	screen = new Screen();
	if( !screen->Show( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP ) )
		return false;
	
	Graphics::GetGraphics()->Load();
	ImageManager::GetManager()->LoadImages(screen);
	
	// Load the background
	layout = new Layout();
	background = layout->CreateBackground();
	
	// Draw the background initially
	RenderManager::GetManager()->LoadScreen(screen);
	RenderManager::GetManager()->LoadBackground(background);
	
	// Create the battle region (the battling section of the game)
	battleRegion = new BattleRegion();
	SDL_Rect battleArea = layout->GetBattleRegionArea();
	battleRegion->SetBoundary( battleArea.x, battleArea.y, battleArea.w, battleArea.h );
	battleRegion->SetTotalHealth(100);
	battleRegion->SetHealth(100);
	battleRegion->SetTotalEnemyHealth(100);
	battleRegion->SetEnemyHealth(100);
	EffectsManager::GetManager()->AddListener(battleRegion);
	
	// Create the player region
	playerRegion = new PlayerRegion();
	SDL_Rect playerArea = layout->GetPlayerRegionArea();
	playerRegion->SetBoundary( playerArea.x, playerArea.y, playerArea.w, playerArea.h );
	playerRegion->SetPlayerName(playerSettings.GetPlayerName());
	playerRegion->LoadCards(playerSettings.CreateDeck());
	
	// Create the card region (the player's hand)
	handRegion = new HandRegion();
	SDL_Rect handArea = layout->GetHandRegionArea();
	handRegion->SetBoundary( handArea.x, handArea.y, handArea.w, handArea.h );
	handRegion->SetPlayerRegion( playerRegion );
	handRegion->GrabCards();
	
	// Create the alignment region
	alignmentRegion = new AlignmentRegion();
	SDL_Rect alignmentArea = layout->GetAlignmentRegionArea();
	alignmentRegion->SetBoundary( alignmentArea.x, alignmentArea.y, alignmentArea.w, alignmentArea.h );
	EffectsManager::GetManager()->AddListener(alignmentRegion);
	
	// Create the queue region
	queueRegion = new QueueRegion();
	SDL_Rect queueArea = layout->GetQueueRegionArea();
	queueRegion->SetBoundary( queueArea.x, queueArea.y, queueArea.w, queueArea.h );
	queueRegion->SetAlignmentRegion(alignmentRegion);
	
	// Create the puzzle region (the player's gem board)
	puzzleRegion = new PuzzleRegion();
	SDL_Rect puzzleArea = layout->GetPuzzleRegionArea();
	puzzleRegion->SetBoundary( puzzleArea.x, puzzleArea.y, puzzleArea.w, puzzleArea.h );
	puzzleRegion->SetQueueRegion(queueRegion);
	
	//puzzleRegion->Start();
	handRegion->SetPuzzleRegion(puzzleRegion);
	
	// Create the top region
	topRegion = new TopRegion();
	topRegion->SetBoundary( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
	RenderManager::GetManager()->SetTopRegion(topRegion);
	
	return true;
}

/**
* Runs the game loop.
**/
void Application::Run()
{
	int ticks = 0;
	SDL_Event event;
	
	paused = true;
	showTop = true;
	topRegion->ShowPlainText("Start!", 1000, this);
	
	// While the user wants the game to continue
    while( !quit )
    {	
    	ticks = SDL_GetTicks();
    	
    	if( !ended && (battleRegion->IsPlayerDead() || puzzleRegion->IsFull()) )
    	{
    		ended = true;
    		paused = showTop = true;
    		topRegion->ShowPlainText("Lose!");
    	}
    	if( !ended && battleRegion->IsEnemyDead() )
    	{
    		ended = true;
    		paused = showTop = true;
    		topRegion->ShowPlainText("Win!");
    	}
    	
    	//While there's events to handle
    	//SDL_Event event;
    	while( SDL_PollEvent( &event ) )
        {            
            // If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                // Quit the program
                quit = true;
            }
            else if( ended )
            {
            	if( event.type == SDL_KEYDOWN )
            	{
            		quit = true;
            	}
            }
            else if( event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE )
        	{
            	// Quit the program
        		quit = true;
        	}
            else if( event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_PAUSE )
        	{
            	paused = !paused;
            	showTop = !showTop;
            	
            	if( showTop )
            	{
            		topRegion->ShowPlainText("Paused!");
            	}
            	else
            	{
            		topRegion->Reset();
            	}
        	}
            else
            {
            	if( event.type == SDL_MOUSEMOTION ) // For tooltips
            	{
            		currentX = event.button.x;
            		currentY = event.button.y;
            		tooltipCounter = 0;
            	}
            	
                // Handle events
            	if( !paused && !showTop )
            	{
	            	handRegion->ProcessEvent( event );
	            	playerRegion->ProcessEvent( event );
	            	queueRegion->ProcessEvent( event );
	            	alignmentRegion->ProcessEvent( event );
	            	puzzleRegion->ProcessEvent( event );
	            	battleRegion->ProcessEvent( event );
            	}
            	else if( showTop )
            	{
            		topRegion->ProcessEvent( event );
            	}
            }
        }
    	
    	// Render
    	puzzleRegion->Render();
    	playerRegion->Render();
    	handRegion->Render();
    	queueRegion->Render();
    	alignmentRegion->Render();
    	battleRegion->Render();
    	
    	if( showTop )
    		topRegion->Render();
    	
    	if( tooltipCounter > TOOLTIP_THRESHOLD )
    	{
    		// tooltip logic goes here..
    		TooltipInfo* info = handRegion->GetTooltipInfo();
    		if( info == NULL )
    			info = alignmentRegion->GetTooltipInfo();
    		
    		if (info)
    		{
				ImageCustomRender* render = new ImageCustomRender();
				render->surface = info->surface;
				render->background = info->background;
				render->x = currentX + 10;
				render->y = currentY + 10;
				render->width = render->surface->GetWidth();
				render->height = render->surface->GetHeight();
				RenderManager::GetManager()->AddCustomRender(render);
    		}
    	}
    	
    	RenderManager::GetManager()->Render();
    	
        // Cap the frame rate, this will have to be done for efficiently later
        if( SDL_GetTicks() - ticks < 1000 / MAX_FRAMERATE )
        {
        	int delay = ( 1000 / MAX_FRAMERATE ) - (SDL_GetTicks() - ticks);
            SDL_Delay( delay );
        }
        
        // Let the region know that time has passed
        if( !paused )
        {
	        puzzleRegion->TimePassed( SDL_GetTicks() - ticks );
	        playerRegion->TimePassed( SDL_GetTicks() - ticks );
	        handRegion->TimePassed( SDL_GetTicks() - ticks );
	        queueRegion->TimePassed( SDL_GetTicks() - ticks );
	        alignmentRegion->TimePassed( SDL_GetTicks() - ticks );
	        battleRegion->TimePassed( SDL_GetTicks() - ticks );
        }
        if( showTop )
        {
        	topRegion->TimePassed( SDL_GetTicks() - ticks );
        }
        // and the effects manager
        EffectsManager::GetManager()->TimePassed( SDL_GetTicks() - ticks );
        
        tooltipCounter += SDL_GetTicks() - ticks;
    }
}

/**
* Signifies the end of a timer.
* 
* Overridden from TopRegionListener
**/
void Application::TimerCompleted()
{
	queueRegion->Initialize();
	puzzleRegion->Start();
	paused = false;
	showTop = false;
}
